home *** CD-ROM | disk | FTP | other *** search
/ Deutsche Edition 1 / Deutsche Edition 1.iso / amok / 011-020 / amok19 / muchmore_1.5 / muchmore.mod < prev    next >
Text File  |  1993-11-04  |  35KB  |  1,071 lines

  1. (*---------------------------------------------------------------------------
  2.   :Program.    MuchMore.mod
  3.   :Author.     Fridtjof Siebert
  4.   :Address.    Nobileweg 67, D-7-Stgt-40
  5.   :Phone.      (0)711/822509
  6.   :Shortcut.   [fbs]
  7.   :Version.    1.5
  8.   :Date.       26-May-89
  9.   :Copyright.  PD
  10.   :Language.   Modula-II
  11.   :Translator. M2Amiga v3.1d
  12.   :Imports     QText  [fbs]
  13.   :History.    26-Nov-88: Now Shows Filelength & Percentage              [fbs]
  14.   :History.    27-Nov-88: Mouse can be used instead of Space / BackSpace [fbs]
  15.   :History.    29-Apr-89: Strong increase in speed, removed WarpText     [fbs]
  16.   :History.    29-Apr-89: Now supports Numeric Keys (Home,PgUp etc.)     [fbs]
  17.   :History.    29-Apr-89: Now opens Screen as big as gfx^.normalDisplay  [fbs]
  18.   :History.    29/30-Apr-89: Asynchronus loading / displaying. Very nice [fbs]
  19.   :History.    30-Apr-89, 00:33: Removed bugs in Filelength & L-Command  [fbs]
  20.   :History.    30-Apr-89, 02:21: Added Find-Command                      [fbs]
  21.   :History.    30-Apr-89, 10:30: Scrolling stops when window is inactive [fbs]
  22.   :History.    01-May-89: Allocates no more unneeded memory for text     [fbs]
  23.   :History.    07-May-89: Allocates even less memory now                 [fbs]
  24.   :History.    14-May-89: Removed deadlock-bug with Find-Window          [fbs]
  25.   :History.    25-May-89: Added print feature                            [fbs]
  26.   :History.    25-May-89: Removed all imports (apart from Arts)          [fbs]
  27.   :History.    26-May-89: inspired by J. Kupfer, I added nk 5 to quit    [fbs]
  28.   :History.    26-May-89: Now handle BS correctly                        [fbs]
  29.   :Contents.   A Soft-Scrolling ASCII-File Printer.
  30.   :Remark.     Usage: MuchMore <FileName>
  31. ---------------------------------------------------------------------------*)
  32.  
  33. MODULE MuchMore; (* $F- $V- $R- $S- I hope that there are no more bugs ! *)
  34.  
  35. FROM SYSTEM     IMPORT ADR, ADDRESS, LONGSET, INLINE, SETREG;
  36. FROM Arts       IMPORT TermProcedure, Assert, dosCmdBuf, startupMsg, wbStarted,
  37.                        Terminate;
  38. FROM Dos        IMPORT Open, Close, oldFile, Read, FileHandlePtr, FileLockPtr,
  39.                        FileInfoBlockPtr, Lock, UnLock, Examine, sharedLock,
  40.                        Execute, newFile, Delay, ParentDir, DupLock, CurrentDir;
  41. FROM Exec       IMPORT GetMsg, ReplyMsg, MessagePtr, WaitPort, AllocMem,
  42.                        FreeMem, MemReqSet, MemReqs, Task, AddTask, RemTask,
  43.                        task, Forbid, Permit, TaskPtr, FindTask, Wait, Signal,
  44.                        AllocSignal, FreeSignal, AvailMem;
  45. FROM Graphics   IMPORT ViewModes, ViewModeSet, FontStyleSet, FontFlagSet, TextAttr,
  46.                        BltClear, OpenFont, CloseFont, TextFontPtr, UCopListPtr,
  47.                        CBump, CMove, CWait, GfxBase, FreeCopList, BitMapPtr;
  48. FROM InputEvent IMPORT Qualifiers, QualifierSet;
  49. FROM Intuition  IMPORT NewScreen, ScreenFlags, ScreenFlagSet, customScreen,
  50.                        OpenScreen, CloseScreen, MakeScreen, RethinkDisplay,
  51.                        ScreenPtr, NewWindow, WindowFlags, WindowFlagSet,
  52.                        IDCMPFlags, IDCMPFlagSet, OpenWindow, CloseWindow,
  53.                        WindowPtr, IntuiMessage, IntuiMessagePtr, GadgetPtr,
  54.                        StringInfo, GadgetFlags, GadgetFlagSet, ActivationFlags,
  55.                        ActivationFlagSet, strGadget, ActivateGadget, ActivateWindow;
  56. FROM Hardware   IMPORT custom;
  57. FROM Workbench  IMPORT WBStartupPtr;
  58. IMPORT Graphics;
  59.  
  60. (*-------------------------------------------------------------------------*)
  61.  
  62. CONST
  63.   title = "                       MuchMore 1.5";
  64.   underln = "                    ==================";
  65.   address = "© 1989 Fridtjof Siebert, Nobileweg 67, D-7000-Stuttgart-40";
  66.   empty = "";
  67.   oom = "Out of Memory!";
  68.   cof = "Can't open File!";
  69.   nil = "NIL:";
  70.   w = TRUE;
  71.   f = FALSE;
  72.   MaxLen = 256;
  73.  
  74. TYPE
  75.   TextLinePtr = POINTER TO TextLine;
  76.   TextLine = RECORD
  77.                next: TextLinePtr;
  78.                prev: TextLinePtr;
  79.                len:  INTEGER;
  80.                size: INTEGER;
  81.                text: ARRAY[0..MaxLen] OF CHAR;
  82.              END;
  83.   LONG = LONGINT;
  84.   String = ARRAY [0..127] OF CHAR;
  85.  
  86. VAR
  87.   Screen: ScreenPtr;           (* Screen that contains the Text     *)
  88.   BM: BitMapPtr;               (* Screen's BitMap                   *)
  89.   Window: WindowPtr;
  90.   MyFont: TextAttr;
  91.   MyFile: FileHandlePtr;       (* For loading Textfile              *)
  92.   FirstLine: TextLinePtr;      (* Saved Text                        *)
  93.   TopLine: TextLinePtr;        (* Points to topmost Line            *)
  94.   BottomLine: TextLinePtr;     (* Last Line displayed on Screen     *)
  95.   LoadLine: TextLinePtr;       (* currently loaded Line             *)
  96.   LastLine: TextLinePtr;       (* Last element of LineList          *)
  97.   Name,IStr,FName: String;     (* Text's Name                       *)
  98.   Buffer: ARRAY[0..511] OF CHAR; (* Buffer for Reading              *)
  99.   RQPos: LONG;                 (* Position within ReadBuffer        *)
  100.   RQLen: LONG;                 (* Number of CHARs in Buffer         *)
  101.   NumLines: INTEGER;           (* Number of Lines on Screen         *)
  102.   NumColumns: INTEGER;         (* Number of Columns on Screen       *)
  103.   AnzLines: LONG;              (* Length of Text in Lines           *)
  104.   Font: TextFontPtr;           (* used Font *)
  105.   MyLock,New: FileLockPtr;
  106.   FileInfo: FileInfoBlockPtr;
  107.   FileLength, TextLength: LONG;
  108.   CopperList, CopperAlt: UCopListPtr;
  109.   Cols: POINTER TO ARRAY[0..3] OF CARDINAL;
  110.   Gfxbase: POINTER TO GfxBase;
  111.   ScreenPos: INTEGER;
  112.   ShowTask: Task;
  113.   ShowStack: ARRAY [0..3999] OF CHAR;
  114.   ShowTaskRunning: BOOLEAN;
  115.   mySig: INTEGER;               (* SignalBit *)
  116.   SignalNewData,SignalAllRead,Done,print: BOOLEAN;
  117.   Me: TaskPtr;
  118.   Info: BOOLEAN;
  119.   MyMsgPtr: IntuiMessagePtr;   (* For receiving Messages            *)
  120.   i: INTEGER;
  121.   Scroll,Fast: BOOLEAN;        (* TRUE = Scroll, FALSE = Wait.      *)
  122.   nili,nilo: FileHandlePtr;
  123.  
  124.   WBSt: WBStartupPtr;
  125.   CommLine: POINTER TO CHAR;
  126.   InQuotes: BOOLEAN;
  127.   ArgPtr: POINTER TO String;
  128.  
  129. (*-------------------------------------------------------------------------*)
  130.  
  131. PROCEDURE Alloc(size: LONG): ADDRESS;
  132.  
  133. VAR a: ADDRESS;
  134.  
  135. BEGIN
  136.   a := AllocMem(size,MemReqSet{memClear});
  137.   Assert(a#NIL,ADR(oom));
  138.   RETURN a;
  139. END Alloc;
  140.  
  141. PROCEDURE Length(VAR s: ARRAY OF CHAR): INTEGER;
  142. VAR l: INTEGER;
  143. BEGIN l := 0; WHILE (l<=HIGH(s)) AND (s[l]#0C) DO INC(l) END; RETURN l;
  144. END Length;
  145.  
  146. PROCEDURE Append(VAR s1: ARRAY OF CHAR; s2: ARRAY OF CHAR);
  147. (* appends s2 to s1 *)
  148. VAR p,q: INTEGER;
  149. BEGIN
  150.   p := Length(s1); q := 0;
  151.   WHILE (p<=HIGH(s1)) AND (q<=HIGH(s2)) AND (p<NumColumns) DO
  152.     s1[p] := s2[q]; INC(p); INC(q)
  153.   END;
  154.   IF p<=HIGH(s1) THEN s1[p] := 0C END;
  155. END Append;
  156.  
  157. PROCEDURE QText(x{0},y{1}: INTEGER;
  158.                 str{8}: ADDRESS;
  159.                 bm{9}: BitMapPtr;
  160.                 tf{10}: TextFontPtr);  (* $E- *)
  161.  
  162. BEGIN
  163. INLINE(
  164. (*0000*) 048E7H,0F0F0H,03429H,00000H,048C2H,0C2C2H,048C0H,0D280H,
  165. (*0010*) 02269H,00008H,0D3C1H,02202H,0E781H,09282H,05381H,0246AH,
  166. (*0020*) 00022H,01018H,06700H,00082H,01600H,0C63CH,00060H,06600H,
  167. (*0030*) 00034H,012BCH,000FEH,0D3C2H,012BCH,000C6H,0D3C2H,012BCH,
  168. (*0040*) 000C6H,0D3C2H,012BCH,000C6H,0D3C2H,012BCH,000C6H,0D3C2H,
  169. (*0050*) 012BCH,000C6H,0D3C2H,012BCH,000FEH,0D3C2H,012BCH,00000H,
  170. (*0060*) 093C1H,060BEH,0903CH,00020H,06A04H,0903CH,00020H,0C07CH,
  171. (*0070*) 000FFH,047F2H,00000H,01293H,0D3C2H,012ABH,000C0H,0D3C2H,
  172. (*0080*) 012ABH,00180H,0D3C2H,012ABH,00240H,0D3C2H,012ABH,00300H,
  173. (*0090*) 0D3C2H,012ABH,003C0H,0D3C2H,012ABH,00480H,0D3C2H,012ABH,
  174. (*00A0*) 00540H,093C1H,06000H,0FF7CH,04CDFH,00F0FH,04E75H);
  175. END QText;
  176.  
  177. (*------------------------  Open Display:  --------------------------------*)
  178.  
  179. PROCEDURE InitScreen();
  180.  
  181. VAR
  182.   NuScreen: POINTER TO NewScreen;
  183.   NuWindow: POINTER TO NewWindow;
  184.  
  185.   PROCEDURE NuWin; (* $E- *)
  186.   BEGIN
  187.     INLINE(0,10,0,0,0,     (* size, pens   *)
  188.            8,1032,1,6656, (* idcmp, flags *)
  189.            0,0,0,0,0,0,   (* gadget, checkmark, title *)
  190.            0,0,0,0,       (* screen, bitmap *)
  191.            0,0,0,0,       (* min/max size *)
  192.            15);           (* customscreen *)
  193.   END NuWin;
  194.  
  195.   PROCEDURE NuScrn(); (* $E- *)
  196.   BEGIN
  197.     INLINE(0,0,0,0,1,0,      (* dimensions, pens *)
  198.            8000H,271,        (* hires,customScreen+ScreenQuiet *)
  199.            0,0,0,0,0,0,0,0); (* font, title, gagdets, bitmap *)
  200.   END NuScrn;
  201.  
  202. BEGIN
  203.  
  204. (*------  Open Screen:  ------*)
  205.  
  206.   WITH MyFont DO
  207.     name := ADR("topaz.font");
  208.     ySize := 8;
  209.     style := FontStyleSet{};
  210.     flags := FontFlagSet{};
  211.   END;
  212.   Font := OpenFont(ADR(MyFont));
  213.   NuScreen := ADR(NuScrn);
  214.   WITH NuScreen^ DO
  215.     NumColumns := Gfxbase^.normalDisplayColumns DIV 32 * 4;
  216.     IF NumColumns>MaxLen THEN NumColumns := MaxLen END;
  217.     width        := 8*NumColumns;
  218.     NumLines := Gfxbase^.normalDisplayRows DIV 8;
  219.     height       := 16*NumLines;
  220.   END;
  221.   Screen := OpenScreen(NuScreen^);
  222.   Assert(Screen#NIL,ADR(oom));
  223.   BM := Screen^.rastPort.bitMap;
  224.   Screen^.height := Screen^.height DIV 2;
  225.   MakeScreen(Screen); RethinkDisplay();
  226.  
  227. (*------  Open Window:  ------*)
  228.  
  229.   NuWindow := ADR(NuWin);
  230.   WITH NuWindow^ DO
  231.     width  := NumColumns*8;
  232.     height := Screen^.height-10;
  233.     screen := Screen;
  234.   END;
  235.   Window := OpenWindow(NuWindow^);
  236.   Assert(Window#NIL,ADR(oom));
  237.  
  238. END InitScreen;
  239.  
  240. (*------  Read one TextLine into a Variable:  ------*)
  241.  
  242. PROCEDURE GetTextLine(): TextLinePtr;
  243. (* returns TRUE if EOF *)
  244.  
  245. VAR
  246.   l: TextLinePtr;
  247.   sz,le: INTEGER;
  248.   c: CHAR;
  249.   txt: ARRAY[0..MaxLen] OF CHAR;
  250.  
  251.   PROCEDURE GetCh();
  252.  
  253.   BEGIN
  254.     IF RQPos=RQLen THEN
  255.       RQLen := Read(MyFile,ADR(Buffer),SIZE(Buffer));
  256.       RQPos := 0;
  257.     END;
  258.     IF RQLen=0 THEN c := 0C ELSE c := Buffer[RQPos]; INC(RQPos); INC(le) END;
  259.   END GetCh;
  260.  
  261. BEGIN
  262.   IF RQLen=0 THEN RETURN NIL END;
  263.   sz := 0;
  264.   le := 0;
  265.   LOOP
  266.     LOOP
  267.       GetCh;
  268.       IF (c#33C) AND (c#233C) THEN EXIT END;
  269.       REPEAT GetCh; c:= CAP(c) UNTIL (c>="?") AND (c<="Z") OR (c=0C);
  270.     END;
  271.     CASE c OF
  272.     11C:
  273.       REPEAT
  274.         txt[sz] := " "; INC(sz);
  275.       UNTIL (sz=NumColumns) OR (sz MOD 8 = 0);
  276.       DEC(sz); |
  277.     10C: DEC(sz,2); IF sz<-1 THEN sz := -1 END |
  278.     12C,0C: EXIT |
  279.     240C,14C: txt[sz] := " " |
  280.     ELSE txt[sz] := c END;
  281.     INC(sz);
  282.     IF sz>=NumColumns THEN EXIT END;
  283.   END;
  284.   l := Alloc(SIZE(TextLine)-MaxLen+sz);
  285.   WITH l^ DO
  286.     len := le; size:= sz;
  287.     WHILE sz>0 DO DEC(sz); text[sz]:=txt[sz] END;
  288.   END;
  289.   RETURN l;
  290. END GetTextLine;
  291.  
  292. (*------  Clear one Line:  ------*)
  293.  
  294. PROCEDURE Clear(BM{8}: BitMapPtr; Line{0}: INTEGER);
  295.  
  296. BEGIN
  297. INLINE(
  298.   0C1D0H,          (*    MULS   bm_BytesPerRow(BM),Line *)
  299.   02268H,00008H,   (*    MOVE.L bm_Planes(BM),A1        *)
  300.   0D3C0H,          (*    ADD.L  Line,A1                 *)
  301.   03210H,          (*    MOVE   bm_BytesPerRow(BM),D1   *)
  302.   05341H,          (*    SUBQ   #1,D1                   *)
  303.   04299H,          (* L: CLR.L  (A1)+                   *)
  304.   04299H,          (*    CLR.L  (A1)+                   *)
  305.   051C9H,0FFFAH);  (*    DBRA   D1,L                    *)
  306. END Clear;
  307.  
  308. (*------  Type one Line of Text:  ------*)
  309.  
  310. PROCEDURE TypeLine(str: ADDRESS; PosY: INTEGER);
  311.  
  312. BEGIN
  313.   Clear(BM,PosY*8); QText(0,8*PosY,str,BM,Font);
  314. END TypeLine;
  315.  
  316. (*------  Write Line at Bottom of Text:  ------*)
  317.  
  318. PROCEDURE AddBottomLine(Line: TextLinePtr; Fast: BOOLEAN);
  319.  
  320. VAR
  321.   i,j: INTEGER;
  322.   trash: LONG;
  323.   source,dest: POINTER TO LONG;
  324.  
  325. BEGIN
  326.   WITH Screen^.viewPort.rasInfo^ DO
  327.     TypeLine(ADR(Line^.text),ScreenPos+NumLines);
  328.     dest := BM^.planes[0];
  329.     INC(dest,8*LONG(ScreenPos)*LONG(NumColumns));
  330.     source := dest;
  331.     INC(source,8*LONG(NumLines)*LONG(NumColumns));
  332.     IF Fast THEN
  333.       INC(ryOffset,8);
  334.       MakeScreen(Screen); RethinkDisplay();
  335.       FOR j:=1 TO NumColumns*2 DO dest^ := source^; INC(dest,4); INC(source,4) END;
  336.     ELSE
  337.       FOR i:=0 TO 7 DO
  338.         INC(ryOffset);
  339.         MakeScreen(Screen); RethinkDisplay();
  340.         FOR j:=1 TO NumColumns DIV 4 DO dest^ := source^; INC(dest,4); INC(source,4) END;
  341.       END;
  342.     END;
  343.     INC(ScreenPos);
  344.     IF ScreenPos=NumLines THEN
  345.       ScreenPos := 0;
  346.       ryOffset := 0;
  347.     END;
  348.   END;
  349. END AddBottomLine;
  350.  
  351. (*------  Write String to Screen:  ------*)
  352.  
  353. PROCEDURE Write(String: ARRAY OF CHAR; Fast: BOOLEAN);
  354.  
  355. VAR text: TextLine;
  356.  
  357. BEGIN
  358.   text := FirstLine^;
  359.   i := Length(String);
  360.   IF i>=NumColumns THEN i := NumColumns-1 END;
  361.   text.text[i+1] := 0C;
  362.   REPEAT text.text[i] := String[i]; DEC(i) UNTIL i<0;
  363.   AddBottomLine(ADR(text),Fast);
  364. END Write;
  365.  
  366. (*------  Scroll down one Line:  ------*)
  367.  
  368. PROCEDURE ScrollDown(Fast: BOOLEAN);
  369. (* Returns TRUE if EOF *)
  370.  
  371. BEGIN
  372.   IF (BottomLine^.next=NIL) AND (MyFile#NIL) THEN
  373.     SignalNewData := w;
  374.     REPEAT UNTIL mySig IN Wait(LONGSET{mySig});
  375.     SignalNewData := f;
  376.   END;
  377.   IF BottomLine^.next#NIL THEN
  378.     BottomLine := BottomLine^.next;
  379.     INC(AnzLines);
  380.     INC(TextLength,BottomLine^.len);
  381.   ELSE RETURN END;
  382.   IF AnzLines>=NumLines THEN
  383.     TopLine := TopLine^.next;
  384.   END;
  385.   AddBottomLine(BottomLine,Fast);
  386. END ScrollDown;
  387.  
  388. (*------  Scroll Up one Line:  ------*)
  389.  
  390. PROCEDURE ScrollUp(Fast: BOOLEAN);
  391.  
  392. VAR
  393.   i,j: INTEGER;
  394.   source,dest: POINTER TO LONG;
  395.  
  396. BEGIN
  397.   IF TopLine^.prev#NIL THEN
  398.     TopLine := TopLine^.prev;
  399.     DEC(TextLength,BottomLine^.len);
  400.     DEC(AnzLines);
  401.     BottomLine := BottomLine^.prev;
  402.     WITH Screen^.viewPort.rasInfo^ DO
  403.       IF ScreenPos=0 THEN
  404.         ryOffset  := NumLines*8;
  405.         ScreenPos := NumLines-1;
  406.       ELSE
  407.         DEC(ScreenPos);
  408.       END;
  409.       TypeLine(ADR(TopLine^.prev^.text),ScreenPos);
  410.       source := BM^.planes[0];
  411.       INC(source,(LONG(ScreenPos)+1)*8*LONG(NumColumns)-4);
  412.       dest := source;
  413.       INC(dest,LONG(NumLines)*LONG(NumColumns)*8);
  414.       IF Fast THEN
  415.         DEC(ryOffset,8);
  416.         MakeScreen(Screen); RethinkDisplay();
  417.         FOR j:=1 TO NumColumns*2 DO dest^ := source^; DEC(dest,4); DEC(source,4) END;
  418.       ELSE
  419.         FOR i:=0 TO 7 DO
  420.           DEC(ryOffset);
  421.           MakeScreen(Screen); RethinkDisplay();
  422.           FOR j:=1 TO NumColumns DIV 4 DO dest^ := source^; DEC(dest,4); DEC(source,4) END;
  423.         END;
  424.       END;
  425.     END;
  426.   END;   (* IF TopLine#NIL ... *)
  427. END ScrollUp;
  428.  
  429. (*------  Undo last Write():  ------*)
  430.  
  431. PROCEDURE DelLine();
  432.  
  433. VAR
  434.   i,j: INTEGER;
  435.   source,dest: POINTER TO LONG;
  436.   text: TextLine;
  437.  
  438. BEGIN
  439.   WITH Screen^.viewPort.rasInfo^ DO
  440.     IF ScreenPos=0 THEN
  441.       ryOffset  := NumLines*8;
  442.       ScreenPos := NumLines-1;
  443.     ELSE
  444.       DEC(ScreenPos);
  445.     END;
  446.     IF TopLine^.prev#NIL THEN
  447.       TypeLine(ADR(TopLine^.prev^.text),ScreenPos)
  448.     ELSE
  449.       TypeLine(ADR(FirstLine^.text),ScreenPos);
  450.     END;
  451.     source := BM^.planes[0];
  452.     INC(source,(LONG(ScreenPos)+1)*8*LONG(NumColumns)-4);
  453.     dest := source;
  454.     INC(dest,LONG(NumLines)*LONG(NumColumns)*8);
  455.     FOR i:=0 TO 7 DO
  456.       DEC(ryOffset);
  457.       MakeScreen(Screen); RethinkDisplay();
  458.       FOR j:=1 TO NumColumns DIV 4 DO dest^ := source^; DEC(dest,4); DEC(source,4) END;
  459.     END;
  460.   END;
  461. END DelLine;
  462.  
  463. (*------  Clear Display:  ------*)
  464.  
  465. PROCEDURE ClearBitMaps();
  466.  
  467. BEGIN
  468.   WITH BM^ DO
  469.     BltClear(planes[0],bytesPerRow*rows,0);
  470.     ScreenPos := 0;
  471.     Screen^.viewPort.rasInfo^.ryOffset := 0;
  472.   END;
  473. END ClearBitMaps;
  474.  
  475. (*------  Convert Integer to String:  ------*)
  476.  
  477. PROCEDURE IntToStr(VAR String: ARRAY OF CHAR;
  478.                        At,Chars: INTEGER;
  479.                        int: LONG);
  480.  
  481. VAR
  482.   Cnt: INTEGER;
  483.   Ziff: LONG;
  484.  
  485. BEGIN
  486.   IF (Length(String)<Chars+At) AND (HIGH(String)>=Chars+At) THEN
  487.     String[Chars+At] := 0C;
  488.   END;
  489.   Cnt := Chars; Ziff := 1;
  490.   WHILE Cnt>1 DO
  491.     Ziff := Ziff * 10;
  492.     DEC(Cnt);
  493.   END;
  494.   Cnt := 0;
  495.   WHILE Cnt<Chars DO
  496.     String[Cnt+At] := "0";
  497.     WHILE int>=Ziff DO
  498.       DEC(int,Ziff);
  499.       INC(String[Cnt+At]);
  500.     END;
  501.     Ziff := Ziff DIV 10;
  502.     INC(Cnt);
  503.   END;
  504.   Cnt := 0;
  505.   WHILE (Cnt<Chars-1) AND (String[Cnt+At]="0") DO
  506.     String[Cnt+At] := " ";
  507.     INC(Cnt)
  508.   END;
  509. END IntToStr;
  510.  
  511. (*-------------------------------------------------------------------------*)
  512.  
  513. PROCEDURE GetLength(t: TextLinePtr);
  514.  
  515. BEGIN
  516.   TextLength := 0; AnzLines := 0;
  517.   WHILE t#NIL DO INC(AnzLines); INC(TextLength,t^.len); t := t^.prev END;
  518. END GetLength;
  519.  
  520. (*-------------------------------------------------------------------------*)
  521.  
  522. PROCEDURE NewDisplay();
  523. (* Zeichnet ab BottomLine neu *)
  524.  
  525. VAR
  526.   i: INTEGER;
  527.   l: TextLinePtr;
  528.  
  529. BEGIN
  530.   ClearBitMaps;
  531.   i := 1;
  532.   l := BottomLine;
  533.   WHILE (i<NumLines) AND (BottomLine^.next#NIL) DO
  534.     BottomLine := BottomLine^.next;
  535.     INC(i);
  536.   END;
  537.   WHILE (i<NumLines) AND (l^.prev#NIL) DO l := l^.prev; INC(i) END;
  538.   BottomLine := l;
  539.   GetLength(l);
  540.   Write(empty,w);
  541.   AddBottomLine(BottomLine,w);
  542.   FOR i:=0 TO NumLines-2 DO
  543.     TopLine := l;
  544.     ScrollDown(w);
  545.   END;
  546.   Scroll := f;
  547. END NewDisplay;
  548.  
  549. (*-------------------------------------------------------------------------*)
  550.  
  551. PROCEDURE ShowProc();
  552.  
  553. VAR
  554.   l: TextLinePtr;
  555.   Down: BOOLEAN;               (* Scroll-Direction                  *)
  556.   End: BOOLEAN;                (* Quit next time Space is pressed ? *)
  557.   i,j,k,m: INTEGER;
  558.   MyMsg: IntuiMessage;         (* contains Message                  *)
  559.   Shift: BOOLEAN;              (* Shifted Keystroke ?               *)
  560.   Alt: BOOLEAN;                (* Altered Keystroke ?               *)
  561.   NuWindow: POINTER TO NewWindow;
  562.   win: WindowPtr;
  563.   StrGadget: GadgetPtr;
  564.   StrInfo: POINTER TO StringInfo;
  565.   Find: ARRAY[0..79] OF CHAR;
  566.   flen: INTEGER;
  567.  
  568.   PROCEDURE NuWin; (* $E- *)
  569.   BEGIN
  570.     INLINE(100,0,0,12,1,  (* size, pens   *)
  571.            8,64,0,4096,   (* idcmp, flags *)
  572.            0,0,0,0,0,0,   (* gadget, checkmark, title *)
  573.            0,0,0,0,       (* screen, bitmap *)
  574.            0,0,0,0,       (* min/max size *)
  575.            15);           (* customscreen *)
  576.   END NuWin;
  577.  
  578.   PROCEDURE StrGdg(); (* $E- *)
  579.   BEGIN
  580.     INLINE(0,0,            (* next *)
  581.            2,2,0,8,        (* size *)
  582.            0,513,          (* flags, activation *)
  583.            strGadget,
  584.            0,0,0,0,0,0,    (* render, selectr., text *)
  585.            0,0,0,0,0);     (* mutualexcl, specialinfo *)
  586.   END StrGdg;
  587.  
  588.   PROCEDURE StrInf(); (* $E- *)
  589.   BEGIN
  590.     INLINE(0,0,0,0,0,   (* buffer, undobuffer, bufferpos *)
  591.            80,0,0,0,    (* maxchars, disppos, undopos, numchars *)
  592.            0,0,0,0,0,
  593.            0,0,0,0);
  594.   END StrInf;
  595.  
  596. BEGIN
  597.  
  598.   Scroll := w; Fast := f; Down := w; End := f; Find := empty;
  599.   LOOP
  600.  
  601. (*------  Type Text:  ------*)
  602.  
  603.     IF Scroll THEN
  604.       IF Down THEN
  605.         ScrollDown(Fast);
  606.         Scroll := (MyFile#NIL) OR (BottomLine^.next#NIL);
  607.       ELSE
  608.         ScrollUp(Fast);
  609.         Scroll := TopLine^.prev#NIL;
  610.       END;
  611.     ELSE
  612.       WaitPort(Window^.userPort);
  613.     END;
  614.  
  615.     MyMsgPtr := ADDRESS(GetMsg(Window^.userPort));
  616.     WHILE (MyMsgPtr#NIL) AND (inactiveWindow IN MyMsgPtr^.class) DO
  617.       WaitPort(Window^.userPort);
  618.       MyMsgPtr := ADDRESS(GetMsg(Window^.userPort));
  619.     END;
  620.  
  621.     IF MyMsgPtr#NIL THEN
  622.  
  623.       MyMsg := MyMsgPtr^;
  624.       ReplyMsg(MessagePtr(MyMsgPtr));
  625.  
  626.       WITH MyMsg DO
  627.  
  628.         IF class=IDCMPFlagSet{mouseButtons} THEN
  629.           class := IDCMPFlagSet{rawKey};
  630.           IF leftButton IN QualifierSet(qualifier) THEN
  631.             code := 40H;
  632.           ELSIF rightButton IN QualifierSet(qualifier) THEN
  633.             code := 41H;
  634.           END;
  635.         END;
  636.  
  637.         IF (class=IDCMPFlagSet{rawKey}) AND (code<80H) THEN
  638.  
  639.           IF Info THEN
  640.             Screen^.viewPort.uCopIns := CopperAlt;
  641.             DelLine();
  642.             Info := f;
  643.           END;
  644.  
  645.           Shift := (lShift   IN QualifierSet(qualifier)) OR
  646.                    (rShift   IN QualifierSet(qualifier)) OR
  647.                    (capsLock IN QualifierSet(qualifier));
  648.  
  649.           Alt   := (lAlt     IN QualifierSet(qualifier)) OR
  650.                    (rAlt     IN QualifierSet(qualifier));
  651.  
  652.           CASE code OF
  653.  
  654.           40H:                                         (* Space *)
  655.                 Fast := Shift;
  656.                 IF (MyFile=NIL) AND (BottomLine^.next=NIL) THEN
  657.                   IF End THEN EXIT ELSE End:=w END;
  658.                 ELSE
  659.                   End := f;
  660.                 END;
  661.                 IF Down THEN
  662.                   IF Scroll OR End THEN
  663. (* File: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines *)
  664.                     IStr := "File: ";
  665.                     Append(IStr,Name);
  666.                     Append(IStr,"                              ");
  667.                     IStr[36] := 0C;
  668.                     Append(IStr,"xxx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines");
  669.                     IntToStr(IStr,36,3,TextLength * 100 DIV FileLength);
  670.                     IntToStr(IStr,43,6,TextLength);
  671.                     IntToStr(IStr,53,6,FileLength);
  672.                     IntToStr(IStr,67,6,AnzLines-1);
  673.                     Write(IStr,f);
  674.                     CopperAlt := Screen^.viewPort.uCopIns;
  675.                     Screen^.viewPort.uCopIns := CopperList;
  676.                     RethinkDisplay();
  677.                     Info := w;
  678.                   END;
  679.                   Scroll := NOT(Scroll);
  680.                 ELSE
  681.                   Down := w;
  682.                   Scroll := w;
  683.                 END; |
  684.  
  685.           41H:                                       (* BackSpace *)
  686.                 Fast := Shift;
  687.                 Scroll := Down OR NOT(Scroll);
  688.                 Down := f |
  689.  
  690.           4DH,1EH,1FH:                                   (* Down *)
  691.                 IF Shift THEN
  692.                   Scroll := NOT(Down AND Scroll) OR NOT(Fast);
  693.                   Fast := w; Down := w;
  694.                 ELSE
  695.                   i:=1; IF Alt OR (code=1FH) THEN i:=NumLines END;
  696.                   WHILE i#0 DO
  697.                     ScrollDown(NOT(Shift));
  698.                     DEC(i);
  699.                   END;
  700.                   Scroll := f;
  701.                 END |
  702.  
  703.           4CH,3EH,3FH:                                        (* Up *)
  704.                 IF Shift THEN
  705.                   Scroll := Down OR NOT(Scroll) OR NOT(Fast);
  706.                   Fast := w; Down := f;
  707.                 ELSE
  708.                   i:=1; IF Alt OR (code=3FH) THEN i:=NumLines END;
  709.                   WHILE i#0 DO
  710.                     ScrollUp(NOT(Shift));
  711.                     Scroll := f;
  712.                     DEC(i);
  713.                   END;
  714.                 END; |
  715.  
  716.           44H,43H:                                        (* CR *)
  717.                 ScrollDown(f);
  718.                 Scroll := f; |
  719.  
  720.           14H,3DH:                                        (* Home *)
  721.                 i:=NumLines-AnzLines;
  722.                 IF i>0 THEN
  723.                   WHILE i>0 DO DEC(i); ScrollDown(w) END; Scroll := f;
  724.                 ELSE
  725.                   BottomLine := FirstLine; NewDisplay();
  726.                 END |
  727.  
  728.           35H,1DH:                                         (* End *)
  729.                 IF MyFile#NIL THEN
  730.                   SignalAllRead := w;
  731.                   REPEAT UNTIL mySig IN Wait(LONGSET{mySig});
  732.                   SignalAllRead := f;
  733.                 END;
  734.                 BottomLine := LastLine;
  735.                 i:=NumLines;
  736.                 WHILE (i>1) AND (BottomLine^.prev#NIL) DO
  737.                   BottomLine := BottomLine^.prev;
  738.                   DEC(i);
  739.                 END;
  740.                 NewDisplay() |
  741.  
  742.           23H,36H:                                        (* Find *)
  743.                 IF code=23H THEN
  744.                   Screen^.height := 2*Screen^.height;
  745.                   MakeScreen(Screen); RethinkDisplay();
  746.                   NuWindow := ADR(NuWin);
  747.                   StrGadget := ADR(StrGdg);
  748.                   StrInfo := ADR(StrInf);
  749.                   WITH NuWindow^ DO
  750.                     topEdge := NumLines*4-6+Screen^.viewPort.rasInfo^.ryOffset;
  751.                     width   := NumColumns*8-200;
  752.                     firstGadget:= StrGadget;
  753.                     screen := Screen;
  754.                     StrGadget^.width := width-4;
  755.                     StrGadget^.specialInfo := StrInfo;
  756.                   END;
  757.                   StrInfo^.buffer := ADR(Find);
  758.                   win := OpenWindow(NuWindow^);
  759.                   IF win=NIL THEN EXIT END;
  760.                   IF ActivateGadget(StrGadget,win,NIL) THEN END;
  761.                   WaitPort(win^.userPort);
  762.                   CloseWindow(win);
  763.                   Screen^.height := Screen^.height DIV 2;
  764.                 END;
  765.                 ClearBitMaps();
  766.                 IF Find[0]#0C THEN
  767.                   IF MyFile#NIL THEN
  768.                     SignalAllRead := w;
  769.                     REPEAT UNTIL mySig IN Wait(LONGSET{mySig});
  770.                     SignalAllRead := f;
  771.                   END;
  772.                   BottomLine := TopLine;
  773.                   flen := Length(Find);
  774.                   LOOP
  775.                     WITH BottomLine^ DO
  776.                       i := 0;
  777.                       IF len<NumColumns THEN m := len ELSE m := NumColumns END;
  778.                       m := m-flen;
  779.                       WHILE i<m DO
  780.                         j := 0; k := i;
  781.                         WHILE CAP(text[k])=CAP(Find[j]) DO
  782.                           INC(j); INC(k);
  783.                           IF Find[j]=0C THEN EXIT END;
  784.                         END;
  785.                         INC(i);
  786.                       END;
  787.                     END;
  788.                     IF BottomLine^.next=NIL THEN EXIT END;
  789.                     BottomLine := BottomLine^.next;
  790.                   END;
  791.                 ELSE
  792.                   BottomLine := TopLine;
  793.                 END;
  794.                 NewDisplay |
  795.  
  796.           19H:                                      (* find previous *)
  797.                 IF Find[0]#0C THEN
  798.                   ClearBitMaps();
  799.                   BottomLine := TopLine;
  800.                   IF BottomLine^.prev#NIL THEN BottomLine:=BottomLine^.prev END;
  801.                   flen := Length(Find);
  802.                   LOOP
  803.                     IF BottomLine^.prev=NIL THEN EXIT END;
  804.                     BottomLine := BottomLine^.prev;
  805.                     WITH BottomLine^ DO
  806.                       i := 0;
  807.                       IF len<NumColumns THEN m := len ELSE m := NumColumns END;
  808.                       m := m-flen;
  809.                       WHILE i<m DO
  810.                         j := 0; k := i;
  811.                         WHILE CAP(text[k])=CAP(Find[j]) DO
  812.                           INC(j); INC(k);
  813.                           IF Find[j]=0C THEN EXIT END;
  814.                         END;
  815.                         INC(i);
  816.                       END;
  817.                     END;
  818.                   END;
  819.                   NewDisplay();
  820.                 END |
  821.  
  822.           18H:  IF Shift AND Alt THEN                    (* Printout *)
  823.                   IStr := "RUN >NIL: TYPE >NIL: "; Append(IStr,FName);
  824.                   Append(IStr," TO PRT:"); print := TRUE; Signal(Me,LONGSET{mySig});
  825.                   REPEAT UNTIL mySig IN Wait(LONGSET{mySig});
  826.                   print := FALSE;
  827.                 END |
  828.  
  829.           5FH,25H: ClearBitMaps(); Write(empty,w);
  830.                 Write(title,w);
  831.                 Write(underln,w);
  832.                 Write(empty,w);
  833.                 Write("Commands:",w);
  834.                 Write(empty,w);
  835.                 Write(" Space, LMB:      Start / Stop scrolling. Quit at end of file.",w);
  836.                 Write(" BackSpace, RMB:  Start / Stop scrolling backwards.",w);
  837.                 Write(" Up/Down:         Move one line up or down.",w);
  838.                 Write(" Shift + Up/Down: Start / Stop quick scrolling up or down.",w);
  839.                 Write(" Alt + Up/Dwn:    Move one page up or down.",w);
  840.                 Write(" PgUp/PgDn:       Move one page up or down.",w);
  841.                 Write(" T, Home:         Jump to first page.",w);
  842.                 Write(" B, End:          Jump to last page.",w);
  843.                 Write(" F:               Find string.",w);
  844.                 Write(" N:               Jump to next occurance of string.",w);
  845.                 Write(" P:               Jump to previous occurance of string.",w);
  846.                 Write(" Shift + Alt + O: Create printout of the text",w);
  847.                 Write(" HELP, H:         Show Commands.",w);
  848.                 Write(" ESC, Q, X, NK 5: Quit.",w);
  849.                 Write(empty,w);
  850.                 Write(address,w);
  851.                 Write(empty,w);
  852.                 LOOP
  853.                   WaitPort(Window^.userPort);
  854.                   MyMsgPtr := ADDRESS(GetMsg(Window^.userPort));
  855.                   IF (rawKey IN MyMsgPtr^.class) AND (MyMsgPtr^.code<128) THEN EXIT END;
  856.                   ReplyMsg(MyMsgPtr);
  857.                 END;
  858.                 ReplyMsg(MyMsgPtr);
  859.                 BottomLine := TopLine;
  860.                 NewDisplay |
  861.  
  862.           10H,45H,32H,2EH: EXIT |                        (* ESC, Q, X, NK 5 *)
  863.  
  864.           ELSE END;   (* CASE code OF *)
  865.         END;   (* IF class=IDCMPFlagSet{rawKey} THEN *)
  866.       END;   (* WITH MyMsg DO *)
  867.     END;   (* IF MyMsgPtr#NIL THEN *)
  868.   END;   (* LOOP *)
  869.  
  870.   Done := w;
  871.   Signal(Me,LONGSET{mySig});
  872.   WHILE w OR (1 IN Wait(LONGSET{})) DO END;
  873.  
  874. END ShowProc;
  875.  
  876. (*------  Print:  ------*)
  877.  
  878. PROCEDURE Print;
  879.  
  880. BEGIN
  881.   IF print THEN
  882.     nili := Open(ADR(nil),oldFile);
  883.     nilo := Open(ADR(nil),newFile);
  884.     SETREG(0,Execute(ADR(IStr ),nili,nilo));
  885.     Delay(20); Close(nili); Close(nilo);
  886.     Signal(ADR(ShowTask),LONGSET{mySig});
  887.   END
  888. END Print;
  889.  
  890. (*------  Usage:  ------*)
  891.  
  892. PROCEDURE Usage;
  893.  
  894. BEGIN
  895.   Write(title,f); Write(underln,f); Write(empty,f);
  896.   Write("A soft-scrolling ASCII-File-Printer.",f); Write(empty,f);
  897.   Write("Usage: ",f); Write(empty,f);
  898.   Write("  MuchMore <FileName>",f); Write(empty,f);
  899.   Write("To start from Workbench click text to print before",f); Write(empty,f);
  900.   Write("shift-doubleclicking MuchMore. ",f); Write(empty,f);
  901.   Write("Texts with MuchMore as their default-tool just have to be doubleclicked",f); Write(empty,f);
  902.   Write("This can be run on NTSC as well as on PAL Amigas.",f); Write(empty,f);
  903.   Write(address,f);
  904.   Write("This is free to be spread on PD or Shareware Disks, as long as",f);
  905.   Write("you leave my name and address in.",f);
  906.   Write("It's illegal to make comercial use of this without my written permission!",f);
  907.   Write(empty,f);
  908.   WaitPort(Window^.userPort);
  909.   Terminate(0);
  910. END Usage;
  911.  
  912. (*------  CleanUp:  ------*)
  913.  
  914. PROCEDURE CleanUp();
  915.  
  916. VAR t: TextLinePtr;
  917.  
  918. BEGIN
  919.   IF ShowTaskRunning THEN RemTask(ADR(ShowTask)) END;
  920.   IF Window#NIL THEN CloseWindow(Window) END;
  921.   IF Screen#NIL THEN
  922.     IF Info THEN Screen^.viewPort.uCopIns := CopperAlt END;
  923.     CloseScreen(Screen)
  924.   END;
  925.   IF MyFile#NIL THEN Close(MyFile) END;
  926.   WHILE FirstLine#NIL DO
  927.     t := FirstLine;
  928.     FirstLine := FirstLine^.next;
  929.     FreeMem(t,SIZE(TextLine)-MaxLen+t^.size);
  930.   END;
  931.   IF MyLock#NIL THEN UnLock(MyLock) END;
  932.   IF New   #NIL THEN UnLock(New   ) END;
  933.   IF FileInfo#NIL THEN FreeMem(FileInfo,SIZE(FileInfo^)) END;
  934.   IF CopperList#NIL THEN
  935.     IF CopperList^.firstCopList#NIL THEN
  936.       FreeCopList(CopperList^.firstCopList);
  937.     END;
  938.     FreeMem(CopperList,SIZE(CopperList^));
  939.   END;
  940.   IF Font#NIL THEN CloseFont(Font) END;
  941.   IF mySig#-1 THEN FreeSignal(mySig) END;
  942. END CleanUp;
  943.  
  944. (*------------------------------  MAIN:  ----------------------------------*)
  945.  
  946. BEGIN
  947.  
  948. (*------  Init:  ------*)
  949.  
  950.   Screen := NIL; Window := NIL; FirstLine := NIL; TopLine := NIL;
  951.   BottomLine := NIL; MyFile := NIL; AnzLines := 0; Font := NIL; Info := f;
  952.   MyLock := NIL; FileInfo := NIL; TextLength := 0; ScreenPos := 0;
  953.   CopperList := NIL; ShowTaskRunning := f; SignalNewData := f;
  954.   SignalAllRead := f; Done := f; print := f; mySig := -1; Me := FindTask(0);
  955.   Gfxbase := ADR(Graphics); New := NIL;
  956.  
  957.   TermProcedure(CleanUp);
  958.  
  959. (*------  Setup:  ------*)
  960.  
  961.   InitScreen();
  962.   Cols := Screen^.viewPort.colorMap^.colorTable;
  963.   FirstLine := Alloc(SIZE(TextLine)-MaxLen);
  964.   FirstLine^.size := 0;
  965.   FirstLine^.text[0] := 0C;
  966.   LastLine := FirstLine;
  967.   BottomLine := FirstLine;
  968.   TopLine := FirstLine;
  969.   AnzLines := 1;
  970.   FileInfo   := Alloc(SIZE(FileInfo^));
  971.   CopperList := Alloc(SIZE(CopperList^));
  972.   CWait(CopperList, Screen^.height-8, 0); CBump(CopperList);
  973.   CMove(CopperList, ADR(custom.color[0]),Cols^[2]); CBump(CopperList);
  974.   CWait(CopperList, Screen^.height, 0); CBump(CopperList);
  975.   CMove(CopperList, ADR(custom.color[0]),Cols^[0]); CBump(CopperList);
  976.   CWait(CopperList, 10000,255);
  977.  
  978. (*------  Start:  ------*)
  979.  
  980.   WBSt:= startupMsg;
  981.   IF wbStarted THEN
  982.     WITH WBSt^ DO
  983.       IF numArgs=2 THEN
  984.         ArgPtr := argList^[1].name; Name := ArgPtr^;
  985.         SETREG(0,CurrentDir(argList^[1].lock));
  986.       ELSE Usage END
  987.     END;
  988.   ELSE
  989.     CommLine:=dosCmdBuf; InQuotes:=FALSE; i:=0;
  990.     WHILE CommLine^=" " DO INC(CommLine) END;
  991.     WHILE (CommLine^>" ") OR InQuotes AND (CommLine^=" ") DO
  992.       IF CommLine^='"' THEN InQuotes := NOT InQuotes ELSE
  993.         Name[i] := CommLine^; IF i<127 THEN INC(i) END END;
  994.       INC(CommLine);
  995.     END;
  996.     IF i=0 THEN Usage END;
  997.     Name[i]:= 0C;
  998.   END;
  999.  
  1000.   MyFile := Open(ADR(Name),oldFile);
  1001.   Assert(MyFile#NIL,ADR(cof));
  1002.   RQPos := -1; RQLen := -1;
  1003.  
  1004.   MyLock := Lock(ADR(Name),sharedLock);
  1005.   Assert(MyLock#NIL,ADR(cof));
  1006.   Assert(Examine(MyLock,FileInfo)#0,ADR(cof));
  1007.   FileLength := FileInfo^.size;
  1008.  
  1009.   i := 1; FName := empty;
  1010.   WHILE MyLock#NIL DO
  1011.     IF (Examine(MyLock,FileInfo)#0) THEN
  1012.       IStr := empty; Append(IStr,FileInfo^.fileName);
  1013.       IF i=0 THEN Append(IStr,"/") ELSE i:=0 END;
  1014.       Append(IStr,FName); FName := IStr;
  1015.     END;
  1016.     New:=ParentDir(MyLock); UnLock(MyLock); MyLock := New; New := NIL;
  1017.   END; i:=0;
  1018.   LOOP CASE FName[i] OF "/": FName[i] := ":"; EXIT | 0C: EXIT ELSE END; INC(i) END;
  1019.  
  1020.   MyLock := NIL;
  1021.  
  1022.   mySig := AllocSignal(-1);
  1023.   IF mySig<0 THEN Terminate(0) END;
  1024.  
  1025.   WITH ShowTask DO
  1026.     spLower := ADR(ShowStack);
  1027.     spUpper := ADR(ShowStack[3996]);
  1028.     spReg   := spUpper;
  1029.     node.type := task;
  1030.     node.name := ADR("Show.MM");
  1031.     node.pri  := 1;
  1032.   END;
  1033.   Forbid();
  1034.     LOOP
  1035.       MyMsgPtr := ADDRESS(GetMsg(Window^.userPort));
  1036.       IF MyMsgPtr=NIL THEN EXIT END;
  1037.       ReplyMsg(MyMsgPtr);
  1038.     END;
  1039.     Window^.userPort^.sigTask := ADR(ShowTask);
  1040.     AddTask(ADR(ShowTask),ADR(ShowProc),NIL);
  1041.     ShowTaskRunning := w;
  1042.   Permit();
  1043.  
  1044.   i := 0;
  1045.   REPEAT
  1046.     INC(i);
  1047.     IF i=20 THEN
  1048.       Assert(AvailMem(MemReqSet{chip,largest})>10000,ADR(oom));
  1049.       i := 0;
  1050.     END;
  1051.     LoadLine := GetTextLine();
  1052.     IF LoadLine=NIL THEN
  1053.       Close(MyFile);
  1054.       MyFile := NIL;
  1055.     ELSE
  1056.       LoadLine^.prev := LastLine;
  1057.       Forbid();
  1058.         LastLine^.next := LoadLine;
  1059.         LastLine := LoadLine;
  1060.       Permit;
  1061.     END;
  1062.     IF SignalNewData THEN Signal(ADR(ShowTask),LONGSET{mySig}) END;
  1063.     Print;
  1064.   UNTIL (MyFile=NIL) OR Done;
  1065.   IF SignalAllRead THEN Signal(ADR(ShowTask),LONGSET{mySig}) END;
  1066.   REPEAT REPEAT UNTIL mySig IN Wait(LONGSET{mySig}); Print UNTIL Done;
  1067.  
  1068. END MuchMore.
  1069.  
  1070.  
  1071.